﻿using System;
using System.Collections.Generic;
using System.Text;

    class SlkToken
    {
        internal SlkToken(string input)
        {
            mInput = input;
            mIterator = 0;

            mLineNumber = 1;
            mLastLineNumber = 1;

            mKeywords["true"] = SlkConstants.TRUE_;
            mKeywords["false"] = SlkConstants.FALSE_;
        }

        internal short get()
        {
            mTokenBuilder.Length = 0;
            mLastToken = mCurToken;
            mLastLineNumber = mLineNumber;
            bool isSkip = true;
            //跳过注释与白空格
            for (; isSkip && CurChar != 0; )
            {
                isSkip = false;
                for (; CurChar != 0 && mWhiteSpaces.IndexOf(CurChar) >= 0; ++mIterator)
                {
                    if (CurChar == '\n') ++mLineNumber;
                    isSkip = true;
                }
                //#引导的单行注释
                if (CurChar != 0 && CurChar == '#')
                {
                    for (; CurChar != 0 && CurChar != '\n'; ++mIterator) ;
                    isSkip = true;
                }
                //C++风格的单行注释与多行注释
                if (CurChar != 0 && CurChar == '/' && (NextChar == '/' || NextChar == '*'))
                {
                    ++mIterator;
                    if (CurChar != 0 && CurChar == '/')
                    {
                        ++mIterator;
                        for (; CurChar != 0 && CurChar != '\n'; ++mIterator) ;
                        isSkip = true;
                    }
                    else if (CurChar != 0 && CurChar == '*')
                    {
                        ++mIterator;
                        for (; CurChar != 0; ++mIterator)
                        {
                            if (CurChar == '\n') ++mLineNumber;
                            if (CurChar == '*' && NextChar == '/')
                            {
                                ++mIterator;
                                ++mIterator;
                                break;
                            }
                        }
                        isSkip = true;
                    }
                }
            }
            if (CurChar == 0)//输入结束
            {
                mCurToken = "<<eof>>";
                return SlkConstants.END_OF_SLK_INPUT_;
            }
            else//关键字、标识符或常数
            {
                if (CurChar == '"' || CurChar == '\'')//引号括起来的名称或关键字
                {
                    int line = mLineNumber;
                    char c = CurChar;
                    for (++mIterator; CurChar != 0 && CurChar != c; ++mIterator)
                    {
                        if (CurChar == '\n') ++mLineNumber;
                        if (CurChar == '\\')
                        {
                            mTokenBuilder.Append(CurChar);
                            ++mIterator;
                            if (CurChar == 0)
                                break;
                        }
                        mTokenBuilder.Append(CurChar);
                    }
                    if (CurChar != 0)
                    {
                        ++mIterator;
                    }
                    else
                    {
                        //::printf("[行 %d ]：字符串无法结束！\n",line);
                    }
                    mCurToken = mTokenBuilder.ToString();
                    return SlkConstants.STRING_;
                }
                else if(mDelimiters.IndexOf(CurChar) >= 0)
                {
                    char c = CurChar;
                     mTokenBuilder.Append(c);
                     mCurToken = mTokenBuilder.ToString();
                    ++mIterator;
                    if (c == '(')
                        return SlkConstants.LPARENTESSIS_;
                    if (c == ')')
                        return SlkConstants.RPARENTESSIS_;
                    if (c == '{')
                        return SlkConstants.LBRACE_;
                    if (c == '}')
                        return SlkConstants.RBRACE_;
                    if (c == ';')
                        return SlkConstants.SEMICOLON_;
                    if (c == ',')
                        return SlkConstants.COMMA_;
                }
                else
                {
                    bool isNum = true;
                    bool isHex = false;
                    if (CurChar == '0' && NextChar == 'x')
                    {
                        isHex = true;
                        mTokenBuilder.Append(CurChar);
                        ++mIterator;
                        mTokenBuilder.Append(CurChar);
                        ++mIterator;
                    }
                    for (; CurChar != 0 && (mDelimiters.IndexOf(CurChar) < 0 && mWhiteSpaces.IndexOf(CurChar) < 0 && mOperators.IndexOf(CurChar) < 0); ++mIterator)
                    {
                        if (CurChar == '#')
                            break;
                        else if (CurChar == '/')
                        {
                            if (NextChar == '/' || NextChar == '*')
                            {
                                break;
                            }
                        }
                        else if (CurChar == '.')
                        {
                            if (!isNum)
                            {
                                break;
                            }
                            else
                            {
                                if (NextChar != 0 && !myisdigit(NextChar, isHex))
                                {
                                    break;
                                }
                            }
                        }
                        else if (!myisdigit(CurChar, isHex))
                        {
                            isNum = false;
                        }
                        mTokenBuilder.Append(CurChar);
                    }
                    mCurToken = mTokenBuilder.ToString();
                    if (mKeywords.ContainsKey(mCurToken))
                        return mKeywords[mCurToken];
                    if (isNum)
                        return SlkConstants.NUMBER_;
                    else
                        return SlkConstants.ID_;
                }
            }
            return SlkConstants.END_OF_SLK_INPUT_;
        }

        internal short peek(int level) // scan next token without consuming it
        {
            short token = 0;
            return token;
        }

        internal string getCurToken()
        {
            return mCurToken;
        }
        internal string getLastToken()
        {
            return mLastToken;
        }
        internal int getLineNumber()
        {
            return mLineNumber;
        }
        internal int getLastLineNumber()
        {
            return mLastLineNumber;
        }

        private void getOperatorToken()
        {
            int st = mIterator;
            switch (CurChar)
            {
                case '+':
                    {
                        ++mIterator;
                        if (CurChar == '+' || CurChar == '=')
                        {
                            ++mIterator;
                        }
                    }
                    break;
                case '-':
                    {
                        ++mIterator;
                        if (CurChar == '-' || CurChar == '=')
                        {
                            ++mIterator;
                        }
                    }
                    break;
                case '>':
                    {
                        ++mIterator;
                        if (CurChar == '=')
                        {
                            ++mIterator;
                        }
                        else if (CurChar == '>')
                        {
                            ++mIterator;
                            if (CurChar == '>')
                            {
                                ++mIterator;
                            }
                            if (CurChar == '=')
                            {
                                ++mIterator;
                            }
                        }
                    }
                    break;
                case '<':
                    {
                        ++mIterator;
                        if (CurChar == '=')
                        {
                            ++mIterator;
                        }
                        else if (CurChar == '<')
                        {
                            ++mIterator;
                            if (CurChar == '=')
                            {
                                ++mIterator;
                            }
                        }
                    }
                    break;
                case '&':
                    {
                        ++mIterator;
                        if (CurChar == '=')
                        {
                            ++mIterator;
                        }
                        else if (CurChar == '&')
                        {
                            ++mIterator;
                            if (CurChar == '=')
                            {
                                ++mIterator;
                            }
                        }
                    }
                    break;
                case '|':
                    {
                        ++mIterator;
                        if (CurChar == '=')
                        {
                            ++mIterator;
                        }
                        else if (CurChar == '|')
                        {
                            ++mIterator;
                            if (CurChar == '=')
                            {
                                ++mIterator;
                            }
                        }
                    }
                    break;
                case '=':
                case '!':
                case '^':
                case '*':
                case '/':
                case '%':
                    {
                        ++mIterator;
                        if (CurChar == '=')
                        {
                            ++mIterator;
                        }
                    }
                    break;
                default:
                    {
                        ++mIterator;
                    }
                    break;
            }
            int ed = mIterator;
            mCurToken = mInput.Substring(st, ed - st);
        }
        private bool isWhiteSpace(char c)
        {
            if (0 == c)
                return false;
            else
                return mWhiteSpaces.IndexOf(c) >= 0;
        }
        private bool isDelimiter(char c)
        {
            if (0 == c)
                return false;
            else
                return mDelimiters.IndexOf(c) >= 0;
        }
        private bool isOperator(char c)
        {
            if (0 == c)
                return false;
            else
                return mOperators.IndexOf(c) >= 0;
        }

        private char CurChar
        {
            get
            {
                char c = (char)0;
                if (mIterator < mInput.Length)
                    c = mInput[mIterator];
                return c;
            }
        }
        private char NextChar
        {
            get
            {
                char c = (char)0;
                if (mIterator + 1 < mInput.Length)
                    c = mInput[mIterator + 1];
                return c;
            }
        }

        private static bool myisdigit(char c, bool isHex)
        {
            bool ret = false;
            if (true == isHex)
            {
                if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
                    ret = true;
                else
                    ret = false;
            }
            else
            {
                if ((c >= '0' && c <= '9'))
                    ret = true;
                else
                    ret = false;
            }
            return ret;
        }

        private string mInput;
        private int mIterator;
        private string mCurToken;
        private string mLastToken;

        private int mLineNumber;
        private int mLastLineNumber;

        private const string mWhiteSpaces = " \t\r\n";
        private const string mDelimiters = "{}()[],;";
        private const string mOperators = "~`!%^&*-+=|:<>?/";
        private Dictionary<string, short> mKeywords = new Dictionary<string, short>();
        private StringBuilder mTokenBuilder = new StringBuilder();
    }
